package com.netty.demo.server.netty.config;

import com.netty.demo.server.netty.model.NettyNetwork;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.util.ResourceUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

/**
 * netty配置文件
 *
 * @author yxl 余秀良
 * @version 1.0
 * <p>date: 2019年09月07日  下午4:24 </p>
 * <p>address: 四川成都 </p>
 */
@Slf4j
public final class NettyConfig {
    /**
     * 读取 netty-network.xml 配置文件
     *
     * @return 返回配置信息集合 格式：List<NettyNetwork>
     * @author 余秀良
     * @version 1.0
     * <p>  date: 2019 - 09 - 20  19:11    </p>
     * <p>  address: 四川成都  </p>
     */
    public static List<NettyNetwork> getServerConfig() {
        Document document = getDocument();
        assert document != null;
        Element rootElement = document.getRootElement();
        List<Element> elements = rootElement.elements();
        return elements.stream().map(element -> {
            NettyNetwork nettyNetwork = new NettyNetwork();
            List<Attribute> attributes = element.attributes();
            attributes.forEach(attribute -> {
                try {
                    Field declaredField = nettyNetwork.getClass().getDeclaredField(attribute.getName());
                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(declaredField.getName(), nettyNetwork.getClass());
                    Method writeMethod = propertyDescriptor.getWriteMethod();
                    writeMethod.invoke(nettyNetwork, attribute.getValue());
                } catch (IntrospectionException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
                    log.error("读取netty-network.xml 转为 bean 对象出错 \n {} \n{}", e.getMessage(), e.getLocalizedMessage());
                    e.printStackTrace();
                }
            });
            return nettyNetwork;
        }).collect(Collectors.toList());
    }

    /**
     * 动态修改 netty-network.xml 配置信息
     *
     * @param nettyNetworkList 修改后的数据
     */
    public static void updateServerConfig(List<NettyNetwork> nettyNetworkList) {
        if (nettyNetworkList == null || nettyNetworkList.size() < 1) {
            return;
        }
        FileOutputStream fileOutputStream = null;
        XMLWriter xmlWriter = null;
        try {
            File nettyNetworkXml = ResourceUtils.getFile("classpath:netty-network.xml");
            Document document = getDocument();
            if (document != null) {
                Element rootElement = document.getRootElement();
                List<Element> elements = rootElement.elements();
                elements.forEach(element -> {
                    nettyNetworkList.forEach(nettyNetwork -> {
                        if (element.getName().equals(nettyNetwork.getName())) {
                            List<Attribute> attributes = element.attributes();
                            attributes.forEach(attribute -> {
                                try {
                                    Field declaredField = nettyNetwork.getClass().getDeclaredField(attribute.getName());
                                    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(declaredField.getName(), nettyNetwork.getClass());
                                    Method readMethod = propertyDescriptor.getReadMethod();
                                    String methodName = readMethod.getName();
                                    String invoke = (String) readMethod.invoke(methodName);
                                    attribute.setValue(invoke);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            });
                        }
                    });
                });
                OutputFormat prettyPrint = OutputFormat.createPrettyPrint();
                fileOutputStream = new FileOutputStream(nettyNetworkXml);
                xmlWriter = new XMLWriter(fileOutputStream, prettyPrint);
                xmlWriter.write(document);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (xmlWriter != null) {
                    xmlWriter.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static Document getDocument() {
        try {
            File nettyNetworkXml = ResourceUtils.getFile("classpath:netty-network.xml");
            SAXReader saxReader = new SAXReader();
            return saxReader.read(nettyNetworkXml);
        } catch (FileNotFoundException | DocumentException e) {
            e.printStackTrace();
        }
        return null;
    }

}
